package com.lry.basic.thread;

import io.netty.util.concurrent.FastThreadLocal;
import org.junit.jupiter.api.Test;


public class InheritableThreadLocalTest {

    @Test
    public void testThreadLocal() {
        //主线程设置了值
        ThreadLocal<Integer> tl = new ThreadLocal<>();
        tl.set(1);

        //但是子线程拿不到
        new Thread(()->{
            System.out.println(tl.get());
        }).start();
    }

    @Test
    public void testFastThreadLocal(){
        FastThreadLocal<Integer> tl = new FastThreadLocal();
        tl.set(1);

        //但是子线程拿不到
        new Thread(()->{
            System.out.println(tl.get());
        }).start();
    }

    //使用InheritableThreadLocal看看
    @Test
    public void testInheritableThreadLocal() throws InterruptedException {
        //主线程设置了值
        InheritableThreadLocal<Integer> tl = new InheritableThreadLocal<>();
        tl.set(1);

        //new Thread里的init会把主线程的inheritableThreadLocals属性深拷贝到子线程的inheritableThreadLocals属性
        //但子线程可以拿得到
        new Thread(()->{
            System.out.println("子线程："+tl.get());
        }).start();

    }

    @Test
    public void testInheritableThreadLocal1() throws InterruptedException {
        int i=1;
        //主线程设置了值
        InheritableThreadLocal<Integer> tl = new InheritableThreadLocal<>();
        tl.set(i);


        new Thread(()->{
            while(true){
                //但子线程始终是初始值，因为只有init才会深拷贝父线程的inheritableThreadLocals属性
                System.out.println("子线程："+tl.get());//始终拿到的是1
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }).start();

        //主线程不停修改
        while(true){
            Thread.sleep(1000);
            i++;
            tl.set(i);
            System.out.println("主线程："+tl.get());
        }
    }


    //解决方案1
    int i = 1;
    @Test
    public void testInheritableThreadLocal2() throws InterruptedException {

        Object obj = new Object();

        //主线程设置了值
        InheritableThreadLocal<Integer> tl = new InheritableThreadLocal<>();
        tl.set(i);

        //new Thread里的init会把主线程的inheritableThreadLocals属性深拷贝到子线程的inheritableThreadLocals属性
        //但子线程可以拿得到
        new Thread(()->{
            synchronized (obj){
                while(true){
                    tl.set(i);
                    System.out.println("子线程："+tl.get());
                    obj.notify();

//                    try {
//                        obj.wait();
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
                    break;
                }
            }

        }).start();

        //主线程不停修改
        synchronized (obj){
            while(true){
                i++;
                obj.notify();//通知子线程修改线程变量
                obj.wait();//释放锁
                tl.set(i);//主线程修改线程变量
                System.out.println("主线程："+tl.get());

                Thread.sleep(1000);
            }
        }
    }


    //解决方案2：
    @Test
    public void testInheritableThreadLocal3() throws InterruptedException {


        //主线程设置了值
        InheritableThreadLocal<Integer> tl = new InheritableThreadLocal<>();
        tl.set(i);

        final Callback[] callback = new Callback[1];

        new Thread(()->{
            //这样还是不行，子线程始终还是最初的值
            //因为这行代码是主线程调用的
             callback[0] = i -> { tl.set(i); };

            while(true){
                System.out.println("子线程："+tl.get());

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Thread.sleep(1000);
        //主线程不停修改
        while(true){
            i++;
            //调用子线程回调函数callback
            callback[0].update(i);
            tl.set(i);//主线程修改线程变量
            System.out.println("主线程："+tl.get());

            Thread.sleep(1000);
        }
    }

    interface Callback{
        void update(int i);
    }

}


